package org.simpleframework.aop;

import org.apache.tools.ant.taskdefs.condition.Or;
import org.simpleframework.aop.annotation.Aspect;
import org.simpleframework.aop.annotation.Order;
import org.simpleframework.aop.aspect.AspectInfo;
import org.simpleframework.aop.aspect.DefaultAspect;
import org.simpleframework.core.BeanContainer;
import org.simpleframework.util.ValidationUtil;

import java.lang.annotation.Annotation;
import java.util.*;

/**
 * @ClassName AspectWeaver
 * @Description
 * @Author 47980
 * @Date 2020/8/10 20:06
 * @Version V_1.0
 **/
public class AspectWeaver {

    private BeanContainer beanContainer;

    public AspectWeaver () {
        this.beanContainer = BeanContainer.getInstance();
    }

    public void doAop() {
        // 1.获取所有的切面类
        Set<Class<?>> aspectSet = beanContainer.getClassesByAnnotation(Aspect.class);

        /**
         * SpringAOP 1.0 版本
         */
//        // 2.将切面类按照不同的切入目标进行切分
//        Map<Class<? extends Annotation>, List<AspectInfo>> categorizedMap = new HashMap<>();
//        if (ValidationUtil.isEmpty(aspectSet)) {return;}
//        for (Class<?> aspectClass: aspectSet) {
//            if (verifyClass(aspectClass)) {
//                categorizeAspect(categorizedMap, aspectClass);
//            } else {
//                throw new RuntimeException("@Aspect and @Order have not been added to the Aspect class," +
//                        "or Aspect class does not extend from DefaultAspect, or the value in Aspect Tag equals @Aspect");
//            }
//        }
//        // 3.按照不同的织入目标分别去按序织入Aspect的逻辑
//        if (ValidationUtil.isEmpty(categorizedMap)) {
//            return;
//        }
//        for (Class<? extends Annotation> category :categorizedMap.keySet()) {
//            weaveByCategory(category, categorizedMap.get(category));
//        }

        /**
         * SpringAOP 2.0 版本
         */
        if (ValidationUtil.isEmpty(aspectSet)) {
            return;
        }
        // 2. 拼装AspectInfoList
        List<AspectInfo> aspectInfoList = packAspectInfoList(aspectSet);
        // 3. 遍历容器里的类
        Set<Class<?>> classSet = beanContainer.getClasses();
        for (Class<?> targetClass : classSet) {
            // 排除AspectClass自身
            if (targetClass.isAnnotationPresent(Aspect.class)) {
                continue;
            }
            // 4. 粗筛符合条件的Aspect
            List<AspectInfo> roughMatchedAspectList = collectRoughMatchedAspectListForSpecificClass(aspectInfoList, targetClass);

            // 5. 尝试进行Aspect的织入
            wrapIfNecessary(roughMatchedAspectList, targetClass);
        }


    }

    private void wrapIfNecessary(List<AspectInfo> roughMatchedAspectList, Class<?> targetClass) {
    }

    private List<AspectInfo> collectRoughMatchedAspectListForSpecificClass(List<AspectInfo> aspectInfoList, Class<?> targetClass) {
        List<AspectInfo> roughMatchedAspectList = new ArrayList<>();
        for (AspectInfo aspectInfo : aspectInfoList) {
            // 粗筛
            if (aspectInfo.getPointcutLocator().roughMatches(targetClass)) {
                roughMatchedAspectList.add(aspectInfo);
            }
        }
        return roughMatchedAspectList;
    }

    private List<AspectInfo> packAspectInfoList(Set<Class<?>> aspectSet) {
        return null;
    }

    /**
     * ----------------------------- 1.0 👇 -------------------------------------------
     */

    /**
     *
     * @param category
     * @param aspectInfoList
     */
    private void weaveByCategory(Class<? extends Annotation> category, List<AspectInfo> aspectInfoList) {
        // 1.获取被代理类的集合
        Set<Class<?>> classSet = beanContainer.getClassesByAnnotation(category);
        if (ValidationUtil.isEmpty(classSet)) {
            return;
        }
        // 2.遍历被代理类，分别为每隔被代理类生成动态代理实例
        for (Class<?> targetClass : classSet) {
            // 创建动态代理对象
            AspectListExecutor aspectListExecutor = new AspectListExecutor(targetClass, aspectInfoList);
            Object proxy = ProxyCreator.createProxy(targetClass, aspectListExecutor);
            // 3.将动态代理对象实例添加到容器里，取代未被代理前的类实例
            beanContainer.addBean(targetClass, proxy);
        }

    }

    /**
     * 将切面类按照不同的织入目标进行切分
     * @param categorizedMap
     * @param aspectClass
     */
    private void categorizeAspect(Map<Class<? extends Annotation>, List<AspectInfo>> categorizedMap, Class<?> aspectClass) {
        Order orderTag = aspectClass.getAnnotation(Order.class);
        Aspect aspectTag = aspectClass.getAnnotation(Aspect.class);
        DefaultAspect defaultAspect = (DefaultAspect) beanContainer.getBean(aspectClass);
        AspectInfo aspectInfo = new AspectInfo(orderTag.value(), defaultAspect);
        if (categorizedMap.containsKey(aspectTag.value())) {
            // 如果织入的joinPoint第一次出现，则以该joinPoint为key，以新创建的List<AspectInfo> 为value
            List<AspectInfo> aspectInfoList = new ArrayList<>();
            aspectInfoList.add(aspectInfo);
            categorizedMap.put(aspectTag.value(), aspectInfoList);
        } else {
            // 如果织入的joinPoint不是第一次出现，则往joinPoint对应的value里添加新的Aspect逻辑
            List<AspectInfo> aspectInfoList = categorizedMap.get(aspectTag.value());
            aspectInfoList.add(aspectInfo);
        }
    }

    /**
     * 框架中一定要遵守给Aspect类添加@Aspect和@Order标签的规范，同时，必须继承自DefaultAspect.class
     * 此外，@Aspect的属性值不能是它本身
     * @param aspectClass
     * @return
     */
    private boolean verifyClass(Class<?> aspectClass) {
        return aspectClass.isAnnotationPresent(Aspect.class) &&
                aspectClass.isAnnotationPresent(Order.class) &&
                DefaultAspect.class.isAssignableFrom(aspectClass) &&
                aspectClass.getAnnotation(Aspect.class).value() != Aspect.class;
    }
}
